home *** CD-ROM | disk | FTP | other *** search
-
- /*DungeonE – prototype game example for the Mac Game book*/
- /*By Ingemar Ragnemalm 1995*/
- /**/
- /*This game is somewhat similar to MemoryGame, in that it uses a grid, represented*/
- /*by an array. The game is a typical (though extremely simplified) dungeon-digging game,*/
- /*where the objective is to collect treasures and fight monsters.*/
-
- /*Representation:*/
- /*The array tileArr holds nearly all information we need. telling what is in each space in the grid.*/
- /*Monsters and treasures are only represented this way. In a real game, you may wish to*/
- /*keep a list of all monster and treasure positions, to avoid scanning for them and to keep more*/
- /*information about each.*/
- /*The game also keeps an array that tells what spaces are known to the player (tilesKnown), and*/
- /*the player position (playerPosition), so we don't have to scan for it all the time.*/
- /*The combat system is extremely simple. If you try moving to an enemy, you have 60% chance to*/
- /*hit it and kill it. If an enemy tries to move to you, it has 50% chance to hit, reducing your hit points*/
- /*by one.*/
- /**/
- /*The program ends when we select "Quit".*/
-
-
- #include <Sound.h>
- #include "MoreFilesExtras.h"
- #include "Icons.h"
- #include "ScriptableFinder.h"
- #include "FullPath.h"
- #include <Controls.h>
-
- /*Size of the array*/
- #define kArraySizeH 45
- #define kArraySizeV 20
-
- short kWindowSizeH = 24;
- short kWindowSizeV = 16;
-
- /*Size of the tiles*/
- #define kTileSizeH 32
- #define kTileSizeV 32
-
-
- /*Number of extra pixels below game graphics*/
- #define kScoreFieldHeight 15
- /*Base line for text, how far from bottom of window*/
- #define kScoreBaseLine 3
-
-
- /*Menu ids*/
- #define appleID 127
- #define fileID 128
-
- /* A macro for taking the abs of a value */
- #define abs(x) (x>0?x:-x)
-
- /* All the possible states of a tile (space in the dungeon) */
- //typedef enum {empty, wall, player, enemy, tempEnemy, gold, exitPos} TileState;
- typedef enum {empty, wall, fakeWall, exitPos, file, folder, app} TileState;
-
- short levelVRefNum = -1;
- long levelParId = 1;
-
- /*The score is a global*/
- long gGold, gExperience;
-
-
- /* The window pointer */
- WindowPtr myWindow = nil;
- WindowPtr invWindow = nil;
- /* Arrays describing the dungeon */
-
- /* What tiles have we seen? */
- Boolean tileKnown[kArraySizeH][kArraySizeV];
- /* What does each tile contain? */
- /* tileArray now only holds static objects */
- TileState tileArray[kArraySizeH][kArraySizeV];
-
- /*Variables describing the player:*/
- //Point playerPosition; -> player->position
- short playerHitPoints = 10; // NOT -> player->value
-
- /* A boolean telling if we should quit yet or not */
- Boolean gDone = false;
- Rect gGameRect;
-
- /*Pictures*/
- PicHandle floorTile;
- PicHandle wallTile;
- PicHandle exitTile;
- PicHandle playerTile;
- PicHandle enemyTile;
- PicHandle goldTile;
- PicHandle fileTile;
- PicHandle folderTile;
- PicHandle appTile;
- PicHandle deadPlayer;
-
- /*All 8 directions as vectors*/
- Point directionTable[8] = { { 0, 1 },
- {-1, 1 },
- {-1, 0 },
- {-1,-1 },
- { 0,-1 },
- { 1,-1 },
- { 1, 0 },
- { 1, 1 }};
-
- ControlHandle scrollH;
- ControlHandle scrollV;
-
- OSErr HFS_ReadCatIndex( // read an indexed catalog entry
- SInt16 pVolume, // the volume
- SInt32 pDirectory, // the directory
- SInt32 pIndex, // the index
- CInfoPBRec *rCatInfo, // returns the data
- unsigned char *rName, // returns the name
- Boolean *rEndOfCatalog); // returns end of catalog
-
- OSErr ReadFSSpecIndex( // read an indexed FSSpec entry
- SInt16 pVolume, // the volume
- SInt32 pDirectory, // the directory
- SInt32 pIndex, // the index
- FSSpec *rFSSpec, // returns the FSSpec
- Boolean *rEndOfCatalog); // returns end of catalog
-
- pascal OSErr GetFDFlags(short vRefNum,
- long dirID,
- ConstStr255Param name,
- Boolean *getBits,
- unsigned short flagBits);
- OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr,
- FSSpecArrayHandle fah);
-
- OSErr FindAProcess(OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN,ProcessInfoRecPtr infoRecToFill);
-
- static Boolean GetIndVRefNum(short which, short *vRefNum, StringPtr name);
- pascal OSErr ResolveAliasFileMountOption(FSSpec *fileFSSpec,
- Boolean resolveAliasChains,
- Boolean *targetIsFolder,
- Boolean *wasAliased,
- Boolean mountRemoteVols);
-
- void PlaySoundAsync(StringPtr soundName);
- static OSErr FSpGetIcon(FSSpec *spec, Handle *iconSuite);
- static void SendODOCToProcess(ProcessSerialNumberPtr psn, FSSpecArrayHandle fah);
- static void DoUpdate();
-
- /************************************************/
- /* Types and variables for game entity handling */
- /************************************************/
-
- /* All the possible kinds of game entities */
- typedef enum {playerEntity, enemyEntity, goldEntity, fileEntity, directoryEntity, applicationEntity} EntityType;
-
- /*Variables describing a game entity*/
- typedef struct GameEntityRecord {
- EntityType kind; /* What kind of entity? */
- Point position; /* Where in the grid? */
- short value; /* Hit points or point value */
- FSSpec spec; /* name of file or directory */
- OSType fileType;
- Handle iconSuite; /* icon Suite */
- struct GameEntityRecord *standingOnEntityItem; /* what item is this entity on top of at the moment? */
- struct GameEntityRecord *previous, *next; /* Next and previous entity in the list */
- } GameEntityRecord;
-
- typedef GameEntityRecord *GameEntityPtr; /* Define a handle type to it */
-
- /* A global pointer is the root of the entity list */
- GameEntityPtr gEntityList = nil;
-
- /* The player entity must be easily accessible */
- GameEntityPtr player;
-
- /* tileArray now only holds static objects */
- /* What entity is in each tile? */
- GameEntityPtr entityArray[kArraySizeH][kArraySizeV];
-
- GameEntityPtr playerEntityItem = nil;
- /*** End of game entity handling types and variables ***/
-
-
- typedef struct HeldItemRecord {
- EntityType kind; /* What kind of entity? */
- FSSpec spec;
- Handle iconSuite;
- struct HeldItemRecord *previous, *next; /* Next and previous item in the list */
- } HeldItemRecord;
- typedef HeldItemRecord *HeldItemPtr; /* Define a handle type to it */
-
- HeldItemPtr heldItemsList = nil;
-
-
- static void ClipToGameArea()
- {
- Rect clip;
-
- SetPort(myWindow);
- clip = myWindow->portRect;
- clip.right -= 15;
- clip.bottom -= 15+ kScoreFieldHeight;
- ClipRect(&clip);
- }
-
- static void UnclipToGameArea()
- {
- Rect clip = {-32000, -32000, 32000, 32000};
-
- SetPort(myWindow);
- ClipRect(&clip);
- }
-
-
- #define kScrollBuffer 5
- static void ScrollIntoView(Point pt)
- {
- short vScroll, hScroll;
- short hDelta = 0, vDelta = 0;
-
- vScroll = GetControlValue(scrollV);
- hScroll = GetControlValue(scrollH);
-
- if( pt.h < hScroll)
- {
- hDelta = -(hScroll - pt.h + kScrollBuffer);
- }
-
- if( pt.h > hScroll + kWindowSizeH -1)
- {
- hDelta = (pt.h - (hScroll + kWindowSizeH)) + kScrollBuffer;
- }
-
- if( pt.v < vScroll)
- {
- vDelta = -(vScroll - (pt.v + kScrollBuffer));
- }
-
- if( pt.v > vScroll + kWindowSizeV - 1)
- {
- vDelta = (pt.v - (vScroll + kWindowSizeV)) + kScrollBuffer;
- }
-
- if(hDelta || vDelta)
- {
- SetControlValue(scrollV, vScroll + vDelta);
- SetControlValue(scrollH, hScroll + hDelta);
-
- InvalRect(&myWindow->portRect);
- DoUpdate();
- }
-
- }
- /* A function that generates a value in the interval 0..range-1 */
-
- static short Rand(short range)
- {
- return (Random () & 0x7fff) % range;
- }; /*Rand*/
-
- /* Draw a tile */
-
- static void DrawTile(short h, short v)
- {
- Rect tileRectangle, boardRect;
- short scV, scH;
-
- SetRect(&tileRectangle, h * kTileSizeH, v * kTileSizeV, (h + 1) * kTileSizeH, (v + 1) * kTileSizeV);
-
- boardRect = gGameRect;
-
- boardRect.bottom -= kScoreFieldHeight;
-
- scV = GetControlValue(scrollV);
- scH = GetControlValue(scrollH);
-
- SetOrigin(scH * kTileSizeH, scV * kTileSizeV);
-
- ClipToGameArea();
-
- if(!RectInRgn(&tileRectangle, myWindow->visRgn))
- {
- SetOrigin(0,0);
- return;
- }
- if ( tileKnown[h][v] )
- {
- switch ( tileArray[h][v] )
- {
- case empty:
- DrawPicture(floorTile, &tileRectangle);
- break;
- case wall:
- DrawPicture(wallTile, &tileRectangle);
- break;
- case fakeWall:
- DrawPicture(wallTile, &tileRectangle);
- break;
- case exitPos:
- DrawPicture(exitTile, &tileRectangle);
- break;
- case app:
- if(entityArray[h][v] && entityArray[h][v]->iconSuite)
- {
- DrawPicture(floorTile, &tileRectangle);
- PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
- }
- else
- DrawPicture(appTile, &tileRectangle);
- break;
- case folder:
- if(entityArray[h][v] && entityArray[h][v]->iconSuite)
- {
- DrawPicture(floorTile, &tileRectangle);
- PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
- }
- else
- DrawPicture(folderTile, &tileRectangle);
- break;
- case file:
- if(entityArray[h][v] && entityArray[h][v]->iconSuite)
- {
- DrawPicture(floorTile, &tileRectangle);
- PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
- }
- else
- DrawPicture(fileTile, &tileRectangle);
- break;
-
- default:
- PaintRect(&tileRectangle);
- }
- if (entityArray[h][v] != nil)
- switch (entityArray[h][v]->kind)
- {
- case playerEntity:
- if(playerHitPoints > 0)
- DrawPicture(playerTile, &tileRectangle);
- else
- DrawPicture(deadPlayer, &tileRectangle);
- break;
- case enemyEntity:
- DrawPicture(enemyTile, &tileRectangle);
- break;
- case goldEntity:
- DrawPicture(goldTile, &tileRectangle);
- break;
- case applicationEntity:
- if(entityArray[h][v]->iconSuite)
- {
- DrawPicture(floorTile, &tileRectangle);
- PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
- }
- else
- DrawPicture(appTile, &tileRectangle);
- break;
- case directoryEntity:
- if(entityArray[h][v]->iconSuite)
- {
- DrawPicture(floorTile, &tileRectangle);
- PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
- }
- else
- DrawPicture(folderTile, &tileRectangle);
- break;
- case fileEntity:
- if(entityArray[h][v]->iconSuite)
- {
- DrawPicture(floorTile, &tileRectangle);
- PlotIconSuite(&tileRectangle,atVerticalCenter | atHorizontalCenter,ttNone,entityArray[h][v]->iconSuite);
- }
- else
- DrawPicture(fileTile, &tileRectangle);
- break;
- default:
- ;
- }
- }
- else
- PaintRect(&tileRectangle);
-
- UnclipToGameArea();
-
- SetOrigin(0,0);
- } /*DrawTile*/
-
- static void ShowAll(void)
- {
- short i, j;
- for(i = 0; i < kArraySizeH; i++)
- for(j = 0; j < kArraySizeV; j++)
- {
- tileKnown[i][j] = true;
- }
- InvalRect(&gGameRect);
- DoUpdate();
- }
-
- static void InvalInventory()
- {
- GrafPtr savePort;
-
- GetPort(&savePort);
- SetPort(invWindow);
- InvalRect(&invWindow->portRect);
- SetPort(savePort);
- }
-
-
- /* NewEntity allocates space for a new entity and puts it in the entity list */
- static HeldItemPtr NewHeldItem()
- {
- HeldItemPtr newEntity;
-
- newEntity = (HeldItemPtr) NewPtr(sizeof(HeldItemRecord));
- if (newEntity == nil) return nil;
- if (heldItemsList != nil)
- {
- heldItemsList->previous = newEntity;
- }
- newEntity->next = heldItemsList;
- newEntity->previous = nil;
- heldItemsList = newEntity;
- InvalInventory();
- return newEntity;
- } /*NewEntity*/
-
- /* MakeEntity builds an entity with the given values and puts it into the entityArray */
- static HeldItemPtr PickUpItem(GameEntityPtr item)
- {
- HeldItemPtr newEntity;
-
- if(item->kind == fileEntity ||item->kind == directoryEntity ||item->kind == applicationEntity)
- {
- newEntity = NewHeldItem();
- if (newEntity == nil) return nil;
-
- newEntity->kind = item->kind;
- newEntity->iconSuite = nil;
- FSpGetIcon(&item->spec, &newEntity->iconSuite);
- newEntity->spec = item->spec;
- }
-
- return newEntity;
- } /*PickUpItem*/
-
- static void OpenItem(GameEntityPtr item)
- {
- if(item)
- {
- FSSpecArrayHandle fah = (FSSpecArrayHandle)NewHandle(0);
-
- AddToFSSpecArrayHandle(&item->spec, fah);
-
- OpenScriptableFinderSelection (fah, false, kAENoReply, nil);
- DisposeHandle((Handle)fah);
-
- if(item->kind == directoryEntity)
- {
- ProcessSerialNumber processSN;
- ProcessInfoRecPtr info;
-
- if(FindAProcess('FNDR', 'MACS', &processSN,nil) == noErr)
- {
- SetFrontProcess(&processSN);
- }
- }
- }
- }
- /* DisposeEntity removes an entity from the list and disposes it. */
- static void DisposeHeldItem(HeldItemPtr doomedEntity)
- {
- if (doomedEntity == nil) return;
- if (doomedEntity->next != nil)
- doomedEntity->next->previous = doomedEntity->previous;
- if (doomedEntity->previous != nil)
- doomedEntity->previous->next = doomedEntity->next;
- if (doomedEntity == heldItemsList)
- heldItemsList = doomedEntity->next;
- if(doomedEntity->iconSuite)
- DisposeIconSuite(doomedEntity->iconSuite, true);
- DisposePtr((Ptr)doomedEntity);
- InvalInventory();
- } /*DisposeEntity*/
-
-
- /* drop held items on the current item */
- static void DropItems(GameEntityPtr item)
- {
- HeldItemPtr newEntity;
-
- if( item == nil)
- {
- FSSpecArrayHandle fah = (FSSpecArrayHandle)NewHandle(0);
- HeldItemPtr items;
-
- for(items = heldItemsList; items; items = items->next)
- {
- AddToFSSpecArrayHandle(&items->spec, fah);
- }
-
- OpenScriptableFinderSelection (fah, false, kAENoReply, nil);
- DisposeHandle((Handle)fah);
- return;
- }
-
- if( item->kind == applicationEntity && heldItemsList)
- {
- FSSpecArrayHandle fah = (FSSpecArrayHandle)NewHandle(0);
- HeldItemPtr items;
- FSSpec appSpec;
- ProcessSerialNumber psn;
- FInfo fndrInfo;
-
- for(items = heldItemsList; items; items = items->next)
- {
- AddToFSSpecArrayHandle(&items->spec, fah);
- }
-
- appSpec = item->spec;
-
- FSpGetFInfo(&appSpec, &fndrInfo);
-
- if(FindAProcess(fndrInfo.fdType, fndrInfo.fdCreator, &psn,nil) == noErr)
- SendODOCToProcess(&psn, fah);
- else
- LaunchApplicationWithDocument(&appSpec,fah);
- DisposeHandle((Handle)fah);
-
- while (heldItemsList != nil) DisposeHeldItem(heldItemsList);
- }
-
- if(item->kind == directoryEntity)
- {
-
- }
- } /*DropItems*/
-
- /*************************************/
- /* Routines for game entity handling */
- /*************************************/
-
- /* NewEntity allocates space for a new entity and puts it in the entity list */
- static GameEntityPtr NewEntity()
- {
- GameEntityPtr newEntity;
-
- newEntity = (GameEntityPtr) NewPtr(sizeof(GameEntityRecord));
- if (newEntity == nil) return nil;
- if (gEntityList != nil)
- {
- gEntityList->previous = newEntity;
- }
- newEntity->next = gEntityList;
- newEntity->previous = nil;
- newEntity->standingOnEntityItem = nil;
- gEntityList = newEntity;
- return newEntity;
- } /*NewEntity*/
-
- /* DisposeEntity removes an entity from the list and disposes it. */
- static void DisposeEntity(GameEntityPtr doomedEntity)
- {
- if (doomedEntity == nil) return;
- if (doomedEntity->next != nil)
- doomedEntity->next->previous = doomedEntity->previous;
- if (doomedEntity->previous != nil)
- doomedEntity->previous->next = doomedEntity->next;
- if (doomedEntity == gEntityList)
- gEntityList = doomedEntity->next;
- if(doomedEntity->iconSuite)
- DisposeIconSuite(doomedEntity->iconSuite, true);
- DisposePtr((Ptr)doomedEntity);
- } /*DisposeEntity*/
-
- enum {
- GenericFloppy,
- GenericServer,
- GenericCDRom,
- GenericHD,
- GenericRAMDisk,
- IomegaBernoulliDisk
- };
-
- static short GetFilesVolumeType(short vRefNum)
- {
- DCtlHandle theDCtl;
- StringPtr theDriverName;
- short theType;
- OSErr theError;
- HParamBlockRec pb;
-
- pb.volumeParam.ioVolIndex = 0; /* use vRefNum */
- pb.volumeParam.ioVRefNum = vRefNum;
- pb.volumeParam.ioNamePtr = nil; /* don't care about name */
- theError = PBHGetVInfoSync(&pb);
-
- if (theError == noErr) {
- theDCtl = GetDCtlEntry(pb.volumeParam.ioVDRefNum);
- if (((**theDCtl).dCtlFlags & (1L << 6)) == 1) { /* RAM or ROM */
- /* RAM => dctlDriver is handle */
- theDriverName = (StringPtr)*((Handle)(**theDCtl).dCtlDriver);
- } else {
- /* ROM => dctlDriver is pointer */
- theDriverName = (StringPtr)(**theDCtl).dCtlDriver;
- }
- theDriverName += 18;
- if (EqualString(theDriverName, "\p.Sony", true, true)) {
- theType = GenericFloppy;
- } else if (EqualString(theDriverName, "\p.AFPTranslator", true,
- true)) {
- theType = GenericServer;
- } else if (EqualString(theDriverName, "\p.AppleCD", true,
- true)) {
- theType = GenericCDRom;
- } else if (EqualString(theDriverName, "\p.EDisk", true,
- true)) {
- theType = GenericRAMDisk;
- } else if (EqualString(theDriverName, "\p.SC/IOMEGA3.4", true,
- true)) {
- theType = IomegaBernoulliDisk;
- } else {
- theType = GenericHD;
- }
- } else {
- theType = GenericHD;
- }
- return theType;
- }
-
- static Boolean _GetIconSuiteForTypeCreator(OSType inCreator, OSType inType, short vRefNum, Handle *outIconSuite)
- {
- DTPBRec dtpb;
- short dtdbRefNum = 0, i;
- OSErr err;
- short resRef, saveResRefNum = CurResFile();
- short count = 0, numMenuItems;
- Str63 appName;
- Handle iconData;
- short volumeType;
-
- if(vRefNum)
- {
- dtpb.ioNamePtr = NULL;
- dtpb.ioVRefNum = vRefNum;
- err = PBDTGetPath(&dtpb);
- }
- else
- {
- dtpb.ioResult = noErr;
- }
-
- if(dtpb.ioResult == noErr)
- {
- dtdbRefNum = dtpb.ioDTRefNum;
-
- volumeType = GetFilesVolumeType(vRefNum);
-
- if(volumeType != GenericServer && volumeType != GenericFloppy )
- {
-
- dtpb.ioCompletion = nil;
- dtpb.ioDTRefNum = dtdbRefNum;
- dtpb.ioNamePtr = appName;
- dtpb.ioIndex = 0;
- dtpb.ioFileCreator = inCreator;
-
- // err = PBDTGetAPPL( &dtpb, FALSE);
-
- if(err == noErr)
- {
- dtpb.ioFileType = inType;
- dtpb.ioTagInfo = 0;
-
- err = NewIconSuite( outIconSuite );
-
- if(!err)
- {
- iconData = NewHandle(1024); //space for icl8
- if(iconData)
- {
- HLock(iconData);
- dtpb.ioDTBuffer = *iconData;
- dtpb.ioDTReqCount = 1024;
- dtpb.ioIconType = kLarge8BitIcon;
-
- err = PBDTGetIconSync(&dtpb);
-
- if(err == noErr)
- {
- err = AddIconToSuite(iconData,*outIconSuite,'icl8');
- HUnlock(iconData);
- }
- else
- {
- DisposeHandle(iconData);
- }
- }
-
- iconData = NewHandle(512); //space for icl4
- if(iconData)
- {
- HLock(iconData);
- dtpb.ioDTBuffer = *iconData;
- dtpb.ioDTReqCount = 512;
- dtpb.ioIconType = kLarge4BitIcon;
-
- err = PBDTGetIconSync(&dtpb);
-
- if(err == noErr)
- {
- err = AddIconToSuite(iconData,*outIconSuite,'icl4');
- HUnlock(iconData);
- }
- else
- {
- DisposeHandle(iconData);
- }
- }
-
-
- iconData = NewHandle(256);
- HLock(iconData);
- if(iconData)
- {
- dtpb.ioDTBuffer = *iconData;
- dtpb.ioDTReqCount = 256;
- dtpb.ioIconType = kLargeIcon;
-
- err = PBDTGetIconSync(&dtpb);
-
- if(err == noErr)
- {
- err = AddIconToSuite(iconData,*outIconSuite,'ICN#');
- HUnlock(iconData);
- return true;
- }
- else
- {
- //if we can't get the 'ICN#', we don't have a mask and can't draw!
- DisposeHandle(iconData);
- DisposeIconSuite(*outIconSuite, true);
- *outIconSuite = nil;
- }
- }
- }
- }
- }
- }
- return false;
- }
-
-
- static Boolean FSpGetHasCustomIcon(const FSSpec *spec)
- {
- Boolean result = false;
- OSErr err = GetFDFlags(spec->vRefNum, spec->parID, spec->name, &result, kHasCustomIcon);
-
- return result;
- }
-
- static OSErr FSpGetIcon(FSSpec *spec, Handle *iconSuite)
- {
- OSErr err;
- CInfoPBRec pb;
- Str31 tempName;
- OSErr error;
- short realVRefNum, vRefNum;
- long parID, dirID;
- StringPtr name;
-
- name = spec->name;
- vRefNum = spec->vRefNum;
- dirID = spec->parID;
-
- /* Protection against File Sharing problem */
- if ( (name == NULL) || (name[0] == 0) )
- {
- tempName[0] = 0;
- pb.hFileInfo.ioNamePtr = tempName;
- pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- else
- {
- pb.hFileInfo.ioNamePtr = (StringPtr)name;
- pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- error = PBGetCatInfoSync(&pb);
- if ( error == noErr )
- {
- if(pb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon || pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias || spec->parID == 1)
- {
- err = GetScriptableFinderFileIcon (spec, false, kAEWaitReply, iconSuite);
- }
- else
- {
- //if its a directory, we will just use the generic directory icon
- if( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) //its not directory
- {
- if(_GetIconSuiteForTypeCreator(pb.hFileInfo.ioFlFndrInfo.fdCreator, pb.hFileInfo.ioFlFndrInfo.fdType, vRefNum, iconSuite) == noErr)
- {
- //go with the generic
- *iconSuite = nil;
- }
- }
- }
- }
- return err;
- }
-
- /* MakeEntity builds an entity with the given values and puts it into the entityArray */
- static GameEntityPtr MakeEntity(EntityType eType, short hPos, short vPos, short value, FSSpec *spec, OSType fileType)
- {
- GameEntityPtr newEntity;
-
- newEntity = NewEntity();
- if (newEntity == nil) return nil;
- newEntity->position.h = hPos;
- newEntity->position.v = vPos;
- newEntity->kind = eType;
- newEntity->value = value;
- newEntity->iconSuite = nil;
- newEntity->fileType = fileType;
- if(spec)
- {
- Handle iconHandle;
- FInfo fndrInfo;
- OSErr err;
-
- newEntity->spec = *spec;
-
- err = FSpGetIcon (&newEntity->spec, &newEntity->iconSuite);
- }
- else
- newEntity->spec.name[0] = 0;
- /* Border checking here would be good for safety */
- entityArray[newEntity->position.h][newEntity->position.v] = newEntity;
- // DrawTile(newEntity->position.h, newEntity->position.v);
- return newEntity;
- } /*MakeEntity*/
-
- /* KillEntity disposes an entity, removes it from EntityArray and erases it */
- static void KillEntity(GameEntityPtr doomedEntity)
- {
- if (doomedEntity == nil) return;
- if (entityArray[doomedEntity->position.h][doomedEntity->position.v] == doomedEntity)
- entityArray[doomedEntity->position.h][doomedEntity->position.v] = nil;
- DrawTile(doomedEntity->position.h, doomedEntity->position.v);
- DisposeEntity(doomedEntity);
- } /*KillEntity*/
-
- /*** End of game entity handling routines ***/
-
- /*** Score handling and display ***/
-
- static void DrawScore()
- {
- Str255 tempString;
- Rect blankRect;
-
- SetPort(myWindow);
-
- blankRect = gGameRect;
- blankRect.top = gGameRect.bottom - kScoreFieldHeight;
- EraseRect(&blankRect);
-
- MoveTo(gGameRect.right * 1 / 5, gGameRect.bottom - kScoreBaseLine);
- DrawString("\pGold: ");
- NumToString(gGold, tempString);
- DrawString(tempString);
-
- MoveTo(gGameRect.right * 2 / 5, gGameRect.bottom - kScoreBaseLine);
- DrawString("\pExperience: ");
- NumToString(gExperience, tempString);
- DrawString(tempString);
-
- MoveTo(gGameRect.right * 3 / 5, gGameRect.bottom - kScoreBaseLine);
- DrawString("\pHit points: ");
- NumToString(playerHitPoints, tempString);
- DrawString(tempString);
-
- if(player->standingOnEntityItem)
- {
- TextSize(9);
- TextFace(bold);
- MoveTo(gGameRect.left + 2, gGameRect.bottom - kScoreBaseLine);
- DrawString(player->standingOnEntityItem->spec.name);
- }
- TextSize(12);
- TextFace(0);
-
- } /*DrawScore*/
-
-
- static void AddScore(long addToGold, long addToExperience)
- {
- gGold += addToGold;
- gExperience += addToExperience;
- DrawScore();
- } /*AddScore*/
-
-
- #define kNumHealthTypes 7
- OSType healthTypes[kNumHealthTypes] = {'MSIE', 'XCEL', 'PPT3','MSWD', 'PWSC', 'WFOS', 'MSNM'};
- static void PayForHealth(void)
- {
- short i;
- if(player->standingOnEntityItem)
- {
- for(i = 0; i < kNumHealthTypes; i++)
- {
- if(player->standingOnEntityItem->fileType == healthTypes[i])
- {
- if(gGold > 100)
- {
- gGold -= 100;
- playerHitPoints++;
- DrawScore();
- PlaySoundAsync("\pBought Health");
- }
- }
- }
- }
- }
-
-
- /* Set all tiles around the player to be known, and draw them if they were not known before. */
-
- static void ShowAroundPlayer()
- {
- short h, v;
-
- ScrollIntoView(player->position);
- for ( h = player->position.h - 1 ; h <= player->position.h + 1 ; h++)
- for ( v = player->position.v - 1 ; v <= player->position.v + 1 ; v++)
- if ( ! tileKnown[h][v] )
- {
- tileKnown[h][v] = true;
- DrawTile(h, v);
- }
- } /*ShowAroundPlayer*/
-
-
- static Boolean FindRandomEmptySpot(Point *freeSpot, Rect *rooms, short numRooms)
- {
- short i;
- short room;
- //lets try real randomness for a little while
- for(i = 1; i <= 50; i++)
- {
- freeSpot->v = Rand(kArraySizeV);
- freeSpot->h = Rand(kArraySizeH);
-
- if(entityArray[freeSpot->h][freeSpot->v] == nil && tileArray[freeSpot->h][freeSpot->v] == empty)
- return true;
- }
-
- //if we got here, we still haven't found an empty spot
- //Choose a random room, then look for a spot in it.
- for(i = 1; i <= 50; i++)
- {
- room = Rand(numRooms);
-
- freeSpot->v = rooms[room].top + Rand(rooms[room].bottom - rooms[room].top);
- freeSpot->h = rooms[room].left + Rand(rooms[room].right - rooms[room].left);
-
- if(entityArray[freeSpot->h][freeSpot->v] == nil && tileArray[freeSpot->h][freeSpot->v] == empty)
- return true;
- }
-
- //finally, walk the room list and find the first empty spot
- for(room = 0; room < numRooms; room++)
- {
- for(freeSpot->v = rooms[room].top; freeSpot->v <= rooms[room].bottom; freeSpot->v ++)
- {
- for(freeSpot->h = rooms[room].left; freeSpot->h <= rooms[room].right; freeSpot->h ++)
- {
- if(entityArray[freeSpot->h][freeSpot->v] == nil && tileArray[freeSpot->h][freeSpot->v] == empty)
- return true;
- }
- }
-
- }
-
- return false;
- }
- /* The level generation routine */
-
- static void CreateLevel()
- {
- Rect roomRect[20];
- short room;
- short height, width;
- short h, v, h1, v1, h2, v2;
- short numRooms;
- short numTreasures, numMonsters;
- short i;
- short fileIndex;
- FSSpec fileSpec;
- long freeSpots = 0;
- short pathLen;
- Handle path;
- Str255 title;
- Boolean done = false;
- /*For each tile position, we set the initial state.*/
- /**/
- /*Here we generate the dungeon randomly, with a rather simple algorithm.*/
- /*Most real games use pre-designed levels, preferrably stored in resources.*/
-
-
- /*Dungeon generation algorithm:*/
- /*We select a number of rooms to be placed, 3-10*/
- /*Each room is randomly assigned a size, and then a position.*/
- /*In each room we may put monsters and/or treasures.*/
- /*From each room except the last, we make a path from the room to the next.*/
- /*This guarantees that all rooms are connected.*/
-
- SetControlValue(scrollV, 0);
- SetControlValue(scrollH, 0);
-
- if(GetFullPath(levelVRefNum,levelParId,nil,&pathLen,&path) == noErr)
- {
- title[0] = (pathLen > 250 ? 250 : pathLen);
- BlockMoveData(*path, &(title[1]), pathLen);
- SetWTitle(myWindow, title);
- }
- else
- SetWTitle(myWindow, "\pDrives");
- /*First fill the entire dungeon with walls!*/
- for ( h = 0 ; h < kArraySizeH ; h++)
- for ( v = 0 ; v < kArraySizeV ; v++)
- tileArray[h][v] = wall;
-
- /*All tiles are unknown when we start*/
- /*This must be in the beginning now, since MakeEntity draws*/
- /*the new entity*/
- for ( h = 0 ; h < kArraySizeH ; h++)
- for ( v = 0 ; v < kArraySizeV ; v++)
- tileKnown[h][v] = false;
-
- /*Dispose all old entities*/
- while (gEntityList != nil) DisposeEntity(gEntityList);
-
- /*Fill the entityArray with nil - there's nobody there!*/
- for ( h = 0 ; h < kArraySizeH ; h++)
- for ( v = 0 ; v < kArraySizeV ; v++)
- entityArray[h][v] = nil;
-
- numRooms = 5 + Rand(5); /*5 to 9 rooms*/
-
- /*Create each room*/
- for ( room = 0 ; room <= numRooms - 1 ; room++)
- {
- height = 1 + Rand(5 - numRooms / 2);
- width = 1 + Rand(5 - numRooms / 2);
- roomRect[room].top = 1 + Rand(kArraySizeV - height - 2);
- roomRect[room].bottom = roomRect[room].top + height;
- roomRect[room].left = 1 + Rand(kArraySizeH - width - 2);
- roomRect[room].right = roomRect[room].left + width;
-
- for ( h = roomRect[room].left ; h <= roomRect[room].right ; h++)
- for ( v = roomRect[room].top ; v <= roomRect[room].bottom ; v++)
- {
- tileArray[h][v] = empty;
- freeSpots++;
- }
- };
-
- /*Make paths between all rooms*/
- for ( room = 0 ; room <= numRooms - 2 ; room++)
- {
- /*We make a path from h1, h2, to h2, v2*/
- h1 = roomRect[room].left + Rand(roomRect[room].right - roomRect[room].left + 1);
- v1 = roomRect[room].top + Rand(roomRect[room].bottom - roomRect[room].top + 1);
- h2 = roomRect[room + 1].left + Rand(roomRect[room + 1].right - roomRect[room + 1].left + 1);
- v2 = roomRect[room + 1].top + Rand(roomRect[room + 1].bottom - roomRect[room + 1].top + 1);
-
- /*First move along the h axis*/
- if ( h1 < h2 )
- for ( h = h1 ; h <= h2 ; h++)
- {
- if(Rand(10) == 0)
- {
- tileArray[h][v1] = fakeWall;
- }
- else
- {
- tileArray[h][v1] = empty;
- }
- freeSpots++;
- }
- else
- for ( h = h1 ; h >= h2 ; h--)
- {
- tileArray[h][v1] = empty;
- freeSpots++;
- }
- /*And then along the v axis*/
- if ( v1 < v2 )
- for ( v = v1 ; v <= v2 ; v++)
- {
- if(Rand(10) == 0)
- {
- tileArray[h2][v] = fakeWall;
- }
- else
- {
- tileArray[h2][v] = empty;
- }
- freeSpots++;
- }
- else
- for ( v = v1 ; v >= v2 ; v--)
- {
- tileArray[h2][v] = empty;
- freeSpots++;
- }
- };
-
- /*Now populate the rooms!*/
- for ( room = 1 ; room <= numRooms - 1 ; room++)
- {
- numTreasures = Rand(3); /*0 to 2 treasures*/
- for ( i = 1 ; i <= numTreasures ; i++)
- {
- h = roomRect[room].left + Rand(roomRect[room].right - roomRect[room].left + 1);
- v = roomRect[room].top + Rand(roomRect[room].bottom - roomRect[room].top + 1);
- if (entityArray[h][v] == nil)
- MakeEntity(goldEntity, h, v, Rand(100) + 1, nil, 'gold');
- // tileArray[h][v] = gold;
- };
- if(Rand(2))
- numMonsters = Rand(2); /*0 to 1 monsters*/
- else
- numMonsters = 0;
-
- for ( i = 1 ; i <= numMonsters; i++)
- {
- h = roomRect[room].left + Rand(roomRect[room].right - roomRect[room].left + 1);
- v = roomRect[room].top + Rand(roomRect[room].bottom - roomRect[room].top + 1);
- if (entityArray[h][v] == nil)
- MakeEntity(enemyEntity, h, v, 2, nil, 'bomb');
- // tileArray[h][v] = enemy;
- };
- };
-
- /*Finally, place the player in the first room and the exit in the last. Also check that the exit is*/
- /*not the same position as the player! (It can happen, since we don't mak sure that rooms don't*/
- /*overlap!)*/
-
- /*Player position:*/
- h = roomRect[0].left + Rand(roomRect[0].right - roomRect[0].left + 1);
- v = roomRect[0].top + Rand(roomRect[0].bottom - roomRect[0].top + 1);
- if (entityArray[h][v] != nil)
- KillEntity(entityArray[h][v]);
- player = MakeEntity(playerEntity, h, v, 5, nil, 'plyr');
- // tileArray[h][v] = player;
- /*Exit position:*/
- h = roomRect[numRooms - 1].left + Rand(roomRect[numRooms - 1].right - roomRect[numRooms - 1].left + 1);
- v = roomRect[numRooms - 1].top + Rand(roomRect[numRooms - 1].bottom - roomRect[numRooms - 1].top + 1);
- /*But please don't overwrite the player with the exit!*/
- if ( h == player->position.h )
- if ( v == player->position.v )
- {
- /*Try another room:*/
- h = roomRect[numRooms - 2].left + Rand(roomRect[numRooms - 2].right - roomRect[numRooms - 2].left + 1);
- v = roomRect[numRooms - 2].top + Rand(roomRect[numRooms - 2].bottom - roomRect[numRooms - 2].top + 1);
-
- /*Still failure? Darn. Just take a space next to the player.*/
- if ( h == player->position.h )
- if ( v == player->position.v )
- if ( h < kArraySizeH )
- h = h + 1;
- else
- h = h - 1;
- };
- /*OK, that's enough. Set the exit!*/
- tileArray[h][v] = exitPos;
-
- //Place the files
- for(fileIndex = 1; !done; fileIndex ++)
- {
- OSErr err = noErr;
- Point freeSpot;
-
- if(levelParId == 1)
- {
- fileSpec.parID = 1;
- done = !GetIndVRefNum(fileIndex, &fileSpec.vRefNum, fileSpec.name);
- }
- else
- err = ReadFSSpecIndex(levelVRefNum,levelParId,fileIndex,&fileSpec, &done);
-
- if(err) done = true;
-
- if(!done)
- {
- if(FindRandomEmptySpot(&freeSpot, roomRect, numRooms))
- {
- long newDirId;
- Boolean isDirectory;
- FInfo fndrInfo;
- Boolean wasAlias;
- FSpGetFInfo(&fileSpec, &fndrInfo);
-
- if(fndrInfo.fdFlags & kIsAlias)
- {
- err = ResolveAliasFileMountOption(&fileSpec,true,&isDirectory,&wasAlias, false);
- }
-
- err = FSpGetDirectoryID(&fileSpec, &newDirId, &isDirectory);
- if(isDirectory)
- {
- MakeEntity(directoryEntity, freeSpot.h, freeSpot.v, 0, &fileSpec, fndrInfo.fdCreator);
- tileArray[freeSpot.h][freeSpot.v] = folder;
- }
- else
- if(fndrInfo.fdType == 'APPL')
- {
- MakeEntity(applicationEntity, freeSpot.h, freeSpot.v, 0, &fileSpec, fndrInfo.fdCreator);
- tileArray[freeSpot.h][freeSpot.v] = app;
- }
- else
- {
- MakeEntity(fileEntity, freeSpot.h, freeSpot.v, 0, &fileSpec, fndrInfo.fdCreator);
- tileArray[freeSpot.h][freeSpot.v] = file;
- }
-
- }
- }
- }
-
- /*All tiles are unknown when we start*/
- /*…except the ones around the player*/
-
- /*Make the spaces around the player known*/
- ShowAroundPlayer();
-
- /*Draw all tiles!*/
- for ( h = 0 ; h < kArraySizeH ; h++)
- for ( v = 0 ; v < kArraySizeV ; v++)
- DrawTile(h, v);
- } /*CreateLevel*/
-
-
- /* Move an enemy */
-
- static void MoveEnemy(GameEntityPtr theEnemy /*short h, short v*/)
- {
- short dist;
- short newh, newv;
- short dir;
-
-
- /*1: decide if we are close to enough to the player to "hear" the player*/
-
- dist = abs(theEnemy->position.h - player->position.h) + abs(theEnemy->position.v - player->position.v); /*City Block distance*/
-
- /*2: Make a suggested destination, newh, newv*/
-
- if ( dist < Rand(15) ) /*Move towards the player*/
- {
- if ( theEnemy->position.h < player->position.h )
- newh = theEnemy->position.h + 1;
- else if ( theEnemy->position.h > player->position.h )
- newh = theEnemy->position.h - 1;
- else
- newh = theEnemy->position.h;
- if ( theEnemy->position.v < player->position.v )
- newv = theEnemy->position.v + 1;
- else if ( theEnemy->position.v > player->position.v )
- newv = theEnemy->position.v - 1;
- else
- newv = theEnemy->position.v;
- }
- else /*Move randomly*/
- {
- dir = Rand(8);
- newh = theEnemy->position.h + directionTable[dir].h;
- newv = theEnemy->position.v + directionTable[dir].v;
- }
-
- /*3: Check what is in the destination and take appropriate action (move, fight)*/
-
- switch ( tileArray[newh][newv] )
- {
- case empty:
- case exitPos:
- case app:
- case file:
- case folder:
- case fakeWall:
- /* tileArray[newh][newv] = tempEnemy; /*We can't use "enemy", since then we might process it again in the same move!*/
- /* tileArray[h][v] = empty;*/
- if (entityArray[newh][newv] == player)
- {
- if ( Rand(10) > 5 ) /*Does it hit?*/
- { /*Enemy hits player!*/
- playerHitPoints--; /*Reduce player hit points*/
- DrawScore(); /*Draw score to display the lower hit points!*/
- if ( playerHitPoints > 0 )
- { /*Player still lives!*/
- if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pPlayer hit"), false) )
- ;
- }
- else
- { /*Player died!*/
- DrawTile(player->position.h, player->position.v);
- PlaySoundAsync("\pPlayer died");
- };
- }
- else
- { /*Miss!*/
- if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pPlayer miss"), false) )
- ;
- }
- }
- else
- if (entityArray[newh][newv] == nil)
- {
- if(theEnemy->standingOnEntityItem)
- {
- entityArray[theEnemy->position.h][theEnemy->position.v] = theEnemy->standingOnEntityItem;
- theEnemy->standingOnEntityItem = nil;
- }
- else
- entityArray[theEnemy->position.h][theEnemy->position.v] = nil;
-
- entityArray[newh][newv] = theEnemy;
- DrawTile(newh, newv);
- DrawTile(theEnemy->position.h, theEnemy->position.v);
- theEnemy->position.h = newh;
- theEnemy->position.v = newv;
- }
- else
- {
- if(theEnemy->standingOnEntityItem)
- {
- entityArray[theEnemy->position.h][theEnemy->position.v] = theEnemy->standingOnEntityItem;
- theEnemy->standingOnEntityItem = nil;
- }
- else
- entityArray[theEnemy->position.h][theEnemy->position.v] = nil;
-
- theEnemy->standingOnEntityItem = entityArray[newh][newv];
- entityArray[newh][newv] = theEnemy;
-
- DrawTile(newh, newv);
- DrawTile(theEnemy->position.h, theEnemy->position.v);
- theEnemy->position.h = newh;
- theEnemy->position.v = newv;
- }
- break;
-
- case wall:
- // case enemy:
- // case gold:
- // case exitPos:
- // case tempEnemy:
- break; /*Don't move to any of these!*/
- }; /*case*/
-
- } /*MoveEnemy*/
-
-
- /* Initialize - create window, load graphics */
-
- static void InitDungeon()
- {
- Rect windowRectangle;
- Rect scrollRect;
- /*Set up the window*/
- SetRect(&windowRectangle, 30, 30, 250, 200);
- invWindow = NewCWindow(nil, &windowRectangle, "\pInventory", true, documentProc, (WindowPtr)-1L, false, 0);
-
- SetRect(&windowRectangle, 0, 40, 15 + kWindowSizeH * kTileSizeH, 55 + kWindowSizeV * kTileSizeV + kScoreFieldHeight);
- myWindow = NewCWindow(nil, &windowRectangle, "\pDrives", true, documentProc, (WindowPtr)-1L, false, 0);
- SetPort(myWindow);
-
- gGameRect = myWindow->portRect;
- gGameRect.bottom -= 15;
- gGameRect.right -= 15;
-
- scrollRect = myWindow->portRect;
- scrollRect.left = scrollRect.right - 15;
- scrollRect.right ++;
- scrollRect.bottom -= 14;
- scrollRect.top --;
- scrollV = NewControl(myWindow,&scrollRect,"\p",true,0,0,kArraySizeV - kWindowSizeV,16,0);
-
- scrollRect = myWindow->portRect;
- scrollRect.top = scrollRect.bottom - 15;
- scrollRect.bottom ++;
- scrollRect.right -= 14;
- scrollRect.left --;
- scrollH = NewControl(myWindow,&scrollRect,"\p",true,0,0,kArraySizeH - kWindowSizeH,16,0);
-
- qd.randSeed = TickCount (); /*Seed the random number generator*/
-
- /*Load all pictures*/
- floorTile = GetPicture(128); /*PICT resource #128.*/
- playerTile = GetPicture(129); /*PICT resource #129.*/
- enemyTile = GetPicture(130); /*PICT resource #130.*/
- goldTile = GetPicture(131); /*PICT resource #131.*/
- wallTile = GetPicture(132); /*PICT resource #132.*/
- exitTile = GetPicture(133); /*PICT resource #133.*/
- fileTile = GetPicture(135);
- folderTile = GetPicture(134);
- appTile = GetPicture(136);
- deadPlayer = GetPicture(137);
- } /*InitDungeon*/
-
-
- /* Set up for a new game */
-
- static void NewGame()
- {
- /* Fill in the tileArr array */
- CreateLevel();
-
- /* Start with a healthy player */
- playerHitPoints = 10;
- gGold = 0;
- gExperience = 0;
- } /*NewGame*/
-
-
- /* ValidMove checks if a tile clickedTile is inside the array bounds *and* near the player */
-
- static Boolean ValidMove(Point clickedTile)
- {
- /* Valid tile?*/
- if ( clickedTile.h >= 0 )
- if ( clickedTile.v >= 0 )
- if ( clickedTile.h < kArraySizeH )
- if ( clickedTile.v < kArraySizeV )
- /* OK, we are inside the game area, clicking in some space! Is it next to the player?*/
- if ( clickedTile.h >= player->position.h - 1 )
- if ( clickedTile.h <= player->position.h + 1 )
- if ( clickedTile.v >= player->position.v - 1 )
- if ( clickedTile.v <= player->position.v + 1 )
- return true;
- /* If that wasn't the case, it wasn't vcalid; return false! */
- return false;
- } /*ValidMove*/
-
-
- /* Try to move the player to the position where we clicked. */
-
- static void MovePlayer(Point clickedTile)
- {
- short h, v;
- GameEntityPtr theEntity;
- Boolean freedOldPlayerSpot = false;
-
- /* Valid move?*/
- if (ValidMove(clickedTile))
- /* Yes! What is there? */
- {
- ScrollIntoView(clickedTile);
- if (entityArray[clickedTile.h][clickedTile.v] != nil)
- {
- switch (entityArray[clickedTile.h][clickedTile.v]->kind)
- {
- case enemyEntity:
- if ( Rand(10) > 4 )
- { /*Hit! Play a "monster died" sound*/
-
- entityArray[clickedTile.h][clickedTile.v]->value--;
- if (entityArray[clickedTile.h][clickedTile.v]->value <= 0)
- { /* Monster died! */
- GameEntityPtr monster;
- PlaySoundAsync("\pEnemy died");
- /* Walk to the space where the monster was.*/
- /*tileArray[player->position.h][player->position.v] = empty;
- tileArray[clickedTile.h][clickedTile.v] = player;*/
-
- monster = entityArray[clickedTile.h][clickedTile.v];
- if(monster->standingOnEntityItem)
- entityArray[clickedTile.h][clickedTile.v] = monster->standingOnEntityItem;
-
- KillEntity(monster);
-
- if(player->standingOnEntityItem && !freedOldPlayerSpot)
- {
- entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
- player->standingOnEntityItem = nil;
- }
- else
- entityArray[player->position.h][player->position.v] = nil;
-
- if(entityArray[clickedTile.h][clickedTile.v] != nil)
- {
- player->standingOnEntityItem = entityArray[clickedTile.h][clickedTile.v];
- }
-
- entityArray[clickedTile.h][clickedTile.v] = player;
-
- DrawTile(player->position.h, player->position.v);
- DrawTile(clickedTile.h, clickedTile.v);
- player->position = clickedTile;
-
- /* Killed a monster! Get experience! Let's say one point for the troll! */
- AddScore(0, 1);
- }
- else /* Monster still lives! */
- {
- }
- }
- else
- { /*Miss! Play the "miss" sound. */
- if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pEnemy miss"), false) )
- ;
- }
- break;
- case goldEntity:
- /* Gold - add score! */
- AddScore(entityArray[clickedTile.h][clickedTile.v]->value, 0);
-
- KillEntity(entityArray[clickedTile.h][clickedTile.v]);
- if(player->standingOnEntityItem)
- {
- entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
- player->standingOnEntityItem = nil;
- }
- else
- entityArray[player->position.h][player->position.v] = nil;
- entityArray[clickedTile.h][clickedTile.v] = player;
-
- DrawTile(player->position.h, player->position.v);
- DrawTile(clickedTile.h, clickedTile.v);
- player->position = clickedTile;
- PlaySoundAsync("\pMoney");
- break;
- case directoryEntity:
- case fileEntity:
- case applicationEntity:
- if(player->standingOnEntityItem)
- {
- entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
- freedOldPlayerSpot = true;
- }
- else
- entityArray[player->position.h][player->position.v] = nil;
-
- player->standingOnEntityItem = entityArray[clickedTile.h][clickedTile.v];
-
-
- entityArray[clickedTile.h][clickedTile.v] = player;
-
- DrawTile(player->position.h, player->position.v);
- DrawTile(clickedTile.h, clickedTile.v);
- DrawScore();
- player->position = clickedTile;
- break;
- } /* case kind */
- }
- else
- switch ( tileArray[clickedTile.h][clickedTile.v] )
- {
- case empty:
- case app:
- case file:
- case folder:
- case fakeWall:
- if(tileArray[clickedTile.h][clickedTile.v] == fakeWall)
- tileArray[clickedTile.h][clickedTile.v] = empty;
-
- if(player->standingOnEntityItem && !freedOldPlayerSpot)
- {
- entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
- player->standingOnEntityItem = nil;
- }
- else
- entityArray[player->position.h][player->position.v] = nil;
-
- if(entityArray[clickedTile.h][clickedTile.v] != nil)
- {
- player->standingOnEntityItem = entityArray[clickedTile.h][clickedTile.v];
- }
- entityArray[clickedTile.h][clickedTile.v] = player;
-
- DrawTile(player->position.h, player->position.v);
- DrawTile(clickedTile.h, clickedTile.v);
- player->position = clickedTile;
- DrawScore();
- break;
- case wall:
- SysBeep(1);
- break;
- case exitPos:
- if(player->standingOnEntityItem && !freedOldPlayerSpot)
- {
- entityArray[player->position.h][player->position.v] = player->standingOnEntityItem;
- player->standingOnEntityItem = nil;
- }
- else
- entityArray[player->position.h][player->position.v] = nil;
- entityArray[clickedTile.h][clickedTile.v] = player;
-
- DrawTile(player->position.h, player->position.v);
- DrawTile(clickedTile.h, clickedTile.v);
- player->position = clickedTile;
-
- if ( noErr != SndPlay(nil, (SndListHandle)GetNamedResource('snd ', "\pNext level"), false) )
- ;
- {
- long newParId;
-
- if(GetParentID(levelVRefNum,levelParId,"\p",&newParId) == noErr)
- {
- levelParId = newParId;
- }
- }
- CreateLevel(); /* Don't quit - make a new level instead */
- break;
- }; /*case*/
- }; /*valid move*/
-
- ShowAroundPlayer();
-
- /* Monsters are allowed to move now!*/
-
- theEntity = gEntityList;
- while (theEntity != nil)
- {
- if (theEntity->kind == enemyEntity)
- MoveEnemy(theEntity);
- theEntity = theEntity->next;
- }
-
- } /*MovePlayer*/
-
- /*
- * ScrollProc is the function used in a call to TrackControl for
- * scrolling a document window.
- */
-
- static pascal void ScrollProc(ControlHandle theControl, short theCode)
-
- { long delta = 0, pageDelta, offset, newLine, realDelta;
-
- if (theCode == 0)
- return;
-
- pageDelta = 5;
-
- switch(theCode) {
- case kControlUpButtonPart:
- delta = -1;
- break;
- case kControlDownButtonPart:
- delta = 1;
- break;
- case kControlPageUpPart:
- delta = -pageDelta;
- break;
- case kControlPageDownPart:
- delta = pageDelta;
- break;
- }
-
- realDelta = GetControlValue(theControl);
-
- SetControlValue(theControl, GetControlValue(theControl) + delta);
-
- realDelta = GetControlValue(theControl) - realDelta; //readjust in case we hit max or min
-
- {
- Rect clip;
- RgnHandle saveClip;
- RgnHandle invalRgn;
-
- SetPort(myWindow);
-
- saveClip = NewRgn();
- invalRgn = NewRgn();
-
- GetClip(saveClip);
-
- clip = gGameRect;
- clip.bottom -= kScoreFieldHeight;
- ClipRect(&clip);
-
- if(theControl == scrollV)
- ScrollRect(&clip,0,-realDelta * kTileSizeV,invalRgn);
- else
- ScrollRect(&clip,-realDelta * kTileSizeH,0,invalRgn);
-
- InvalRgn(invalRgn);
- SetClip(saveClip);
- DisposeRgn(saveClip);
- DisposeRgn(invalRgn);
- DoUpdate();
- }
- }
-
- /* Handle mouse downs */
-
- static void DoMouse(Point clickPoint, long mods)
- {
- Point clickedTile;
- short h, v, part;
- ControlHandle ctl;
-
- SetPort(myWindow);
- /*Convert clickPoint to local coordinates*/
- GlobalToLocal(&clickPoint);
-
- part = FindControl(clickPoint,myWindow,&ctl);
- if(part && ctl)
- {
- short value, scrollAmt =0;
-
- if(part == kControlIndicatorPart)
- {
- value = GetControlValue(ctl);
- part = TrackControl(ctl,clickPoint,nil);
- if(part)
- {
- scrollAmt = GetControlValue(ctl) - value;
- }
- }
- else
- {
- ControlActionUPP controlAction;
-
- controlAction = NewControlActionProc(ScrollProc);
- TrackControl(ctl, clickPoint, controlAction);
- DisposeRoutineDescriptor(controlAction);
- }
-
- /* if(scrollAmt)
- {
- Rect clip;
- RgnHandle saveClip;
- RgnHandle invalRgn;
-
- SetControlValue(ctl, GetControlValue(ctl) + scrollAmt);
- saveClip = NewRgn();
- invalRgn = NewRgn();
-
- GetClip(saveClip);
-
- clip = gGameRect;
- clip.bottom -= kScoreFieldHeight;
- ClipRect(&clip);
-
- if(ctl == scrollV)
- ScrollRect(&clip,0,32 * kTileSizeV,invalRgn);
- else
- ScrollRect(&clip,32 * kTileSizeH,0,invalRgn);
-
- InvalRgn(invalRgn);
- SetClip(saveClip);
- DisposeRgn(saveClip);
- DisposeRgn(invalRgn);
- }
- */ }
- else
- {
- /* If the hero is dead, we can't move! */
- if ( playerHitPoints < 1 )
- {
- SysBeep(1);
- return;
- };
-
- /*Convert it to coordinates in the arrays.*/
- clickedTile.h = clickPoint.h / kTileSizeH;
- clickedTile.v = clickPoint.v / kTileSizeV;
- MovePlayer(clickedTile);
- }
- } /*DoMouse*/
-
-
- /* Empty stub for a background task. */
-
- static void DoBackground()
- {
- } /*DoBackground*/
-
-
- /* Add two points - simplifies the keydown handler */
-
- static Point AddPoints(Point p1,Point p2)
- {
- Point dest;
-
- dest.h = p1.h + p2.h;
- dest.v = p1.v + p2.v;
- return dest;
- }; /*AddPoints*/
-
-
- /* Handle key downs */
-
- static void DoKey(char theKey, long mods)
- {
- /* If the hero is dead, we can't move! */
- if ( playerHitPoints < 1 )
- {
- SysBeep(1);
- return;
- };
-
- /* For now, we use a hard-coded key mapping. */
- switch ( theKey )
- {
- case '^':
- ShowAll();
- break;
- case '$':
- PayForHealth();
- break;
- case 'd':
- case '6':
- MovePlayer(AddPoints(player->position, directionTable[0]));break;
- case 'e':
- case '9':
- MovePlayer(AddPoints(player->position, directionTable[1]));break;
- case 'w':
- case '8':
- MovePlayer(AddPoints(player->position, directionTable[2]));break;
- case 'q':
- case '7':
- MovePlayer(AddPoints(player->position, directionTable[3]));break;
- case 'a':
- case '4':
- MovePlayer(AddPoints(player->position, directionTable[4]));break;
- case 'z':
- case '1':
- MovePlayer(AddPoints(player->position, directionTable[5]));break;
- case 'x':
- case '2':
- MovePlayer(AddPoints(player->position, directionTable[6]));break;
- case 'c':
- case '3':
- MovePlayer(AddPoints(player->position, directionTable[7]));break;
-
- case 'o':
- OpenItem(player->standingOnEntityItem);
- break;
-
- case 'g':
- if(player->standingOnEntityItem)
- {
- PickUpItem(player->standingOnEntityItem);
- }
- break;
- case 0x0d:
- DropItems(player->standingOnEntityItem);
- break;
-
- case 0x03:
- if(player->standingOnEntityItem)
- {
- if(player->standingOnEntityItem->kind == directoryEntity)
- {
- FSSpec spec;
- long newDirId;
- Boolean isDir;
-
- spec = player->standingOnEntityItem->spec;
-
- FSpGetDirectoryID(&spec, &newDirId, &isDir);
-
- if(isDir) //sanityCheck
- {
- levelParId = newDirId;
- levelVRefNum = spec.vRefNum;
- CreateLevel(); /* Don't quit - make a new level instead */
- player->standingOnEntityItem = nil;
- }
- }
- }
- break;
- default:
- SysBeep(1);
- }; /*case*/
- }; /*DoKey*/
-
-
- /* Handle selections in the File menu */
-
- static void DoFileMenu(short item)
- {
- switch ( item )
- {
- case 1:
- NewGame();break;
- case 3:
- gDone = true;break;
- }; /*case*/
- }; /*DoFileMenu*/
-
-
- /* The "About" item was selected */
-
- static void DoAbout()
- {
- short ignore;
-
- ignore = Alert(128, nil);
- }; /*DoAbout*/
-
-
- /* Handle update events */
-
- static void DoUpdate()
- {
- short h, v;
-
- SetPort(myWindow);
-
- BeginUpdate(myWindow);
-
- /*Draw all tiles!*/
- for ( h = 0 ; h < kArraySizeH ; h++)
- for ( v = 0 ; v < kArraySizeV ; v++)
- DrawTile(h, v);
-
- DrawScore();
-
- EndUpdate(myWindow);
- DrawGrowIcon(myWindow);
- DrawControls(myWindow);
- }; /*DoUpdate*/
-
- static void UpdateInventory()
- {
- Rect rect;
- HeldItemPtr items;
-
- BeginUpdate(invWindow);
-
- SetPort(invWindow);
- TextFont(applFont);
- TextSize(12);
-
- rect.top = 5;
- rect.left = 5;
- rect.bottom = rect.top + 32;
- rect.right = rect.left + 32;
-
-
- items = heldItemsList;
- while(items)
- {
- if(items->iconSuite)
- PlotIconSuite(&rect,atVerticalCenter | atHorizontalCenter, ttNone, items->iconSuite);
-
- MoveTo(rect.right + 10, rect.bottom - 10);
- DrawString(items->spec.name);
-
- OffsetRect(&rect, 0,34);
- items = items->next;
- }
-
- EndUpdate( invWindow);
- }
-
-
- /* Handle menu selections */
-
- static void DoMenuSelection(long mSelect)
- {
- short menuID;
- short menuItem;
- GrafPtr savePort;
- Str255 name;
- short ignore;
-
- menuID = HiWord(mSelect);
- menuItem = LoWord(mSelect);
-
- switch ( menuID )
- {
- case appleID:
- if ( menuItem == 1 )
- DoAbout();
- else
- {
- GetPort(&savePort);
- GetMenuItemText(GetMenuHandle(appleID), menuItem, name);
- ignore = OpenDeskAcc(name);
- SetPort(savePort);
- };
- break;
- case fileID:
- DoFileMenu(menuItem);break;
- default:
- ;}; /*case*/
- HiliteMenu(0);
- }; /*DoMenuSelection*/
-
-
- /* Set up menus */
-
- static void SetupMenus()
- {
- MenuHandle appleMenu, fileMenu;
- Str255 tempStr;
-
- tempStr[0]=1; tempStr[1] = (char)20;
- appleMenu = NewMenu(appleID, tempStr); /*Apple menu symbol*/
- InsertMenu(appleMenu, 0);
- AppendMenu(appleMenu, "\pAbout Dungeon…;(-");
- AppendResMenu(appleMenu, 'DRVR');
-
- fileMenu = GetMenu(128);
- InsertMenu(fileMenu, 0);
- DrawMenuBar ();
-
- }; /*SetupMenus*/
-
-
- /* Main event loop */
-
- static void MainLoop(void)
- {
- #define kSleep 5 /*Real programs may modify the sleep time depending on whether or not they are in the front*/
-
- EventRecord theEvent;
- char theKey;
- long whatSelection;
- short whichPart;
- WindowPtr whichWindow;
- Rect r;
- Point diskInitPt = {40,40};
-
- /*Get the next event with WaitNextEvent.*/
- if ( WaitNextEvent(everyEvent, &theEvent, kSleep, nil) )
- switch ( theEvent.what )
- {
- case mouseDown:
- /*We must find out what kind of mouse down this was.*/
- whichPart = FindWindow(theEvent.where, &whichWindow);
- switch ( whichPart )
- {
- case inMenuBar:
- /*Click in menu bar. Let the system call MenuSelect track it.*/
- whatSelection = MenuSelect(theEvent.where);
- DoMenuSelection(whatSelection); /*Our own routine for handling menu selections*/
- break;
- case inSysWindow:
- /*Click in some window that isn't ours*/
- SystemClick(&theEvent, whichWindow);
- break;
- case inGoAway:
- /*Click in close box of window. For "desk accessory"-style games, that is a good quit signal*/
- if ( (TrackGoAway(whichWindow, theEvent.where)) )
- gDone = true;
- break;
- case inDrag:
- /*Drag a window*/
- if ( (whichWindow != FrontWindow ()) && ((theEvent.modifiers, cmdKey) == 0) )
- SelectWindow(whichWindow);
- DragWindow(whichWindow, theEvent.where, &qd.screenBits.bounds);
- break;
- case inGrow:
- ; /*Ignored - we don't resize*/
- break;
- case inContent:
- /*Click in the window.*/
- if ( (whichWindow != FrontWindow ()) )
- SelectWindow(whichWindow);
- else
- DoMouse(theEvent.where, theEvent.modifiers); /*Go to application-specific mouse down handling*/
- }; /*case whichPart*/
- break; /*mouseDown*/
- case keyDown:
- case autoKey:
- if(myWindow)
- SetPort(myWindow);
- /*If the command key is pressed, it is a menu selection*/
- theKey = (char)(theEvent.message & charCodeMask);
- if ( ((theEvent.modifiers & cmdKey) != 0) )
- DoMenuSelection(MenuKey(theKey)); /*Our own routine for handling menu selections*/
- else
- /*Otherwise, it's a normal key down.*/
- DoKey(theKey, theEvent.modifiers);
- break;
- case updateEvt:
- /*Find out what event the update event is for.*/
- if ( (WindowPtr)theEvent.message == myWindow )
- DoUpdate();
-
- if( (WindowPtr)theEvent.message == invWindow)
- UpdateInventory();
- break;
- case diskEvt:
- /*Handle bad disk insertions*/
- if (HiWord(theEvent.message) != noErr)
- {
- DILoad();
- DIBadMount(diskInitPt, theEvent.message);
- DIUnload();
- }
- break;
- default: /*Other events are ignored*/
- ;}; /*case*/
-
- /*For each turn to the event loop, we may to call some "background" process, e.g. animations.*/
- DoBackground();
- } /*MainLoop*/
-
-
- /* Standard inits */
-
- static void InitToolbox(void) {
- InitGraf (&qd.thePort);
- InitFonts ();
- FlushEvents (everyEvent,0);
- InitWindows ();
- InitMenus ();
- TEInit ();
- InitDialogs (nil);
- InitCursor ();
- }
-
-
- /* Main program */
-
- void main(void)
- {
- InitToolbox();
- InitDungeon();
- SetupMenus();
- NewGame();
- /*Initializations done! Run the game loop until the game ends.*/
- do
- {
- MainLoop();
- } while (! gDone);
- } /*Dungeon*/
-
-
- OSErr ReadFSSpecIndex( // read an indexed FSSpec entry
- SInt16 pVolume, // the volume
- SInt32 pDirectory, // the directory
- SInt32 pIndex, // the index
- FSSpec *rFSSpec, // returns the FSSpec
- Boolean *rEndOfCatalog) // returns end of catalog
- {
- OSErr rResult;
- CInfoPBRec vCatInfo;
-
- rFSSpec->vRefNum = pVolume;
- rFSSpec->parID = pDirectory;
- rResult = HFS_ReadCatIndex(pVolume, pDirectory, pIndex, &vCatInfo, rFSSpec->name, rEndOfCatalog);
-
- return rResult;
- }
-
- /*
- _ZeroBlock
- */
- static void _ZeroBlock(Ptr pBlock, long pSize)
- {
- long x;
-
- for(x=0;x<pSize;x++) *pBlock++ = 0;
- }
-
- typedef union tHFS_PBRecTag
- {
- CInfoPBRec cInfo;
- HFileInfo hFileInfo;
- DirInfo dirInfo;
- HParamBlockRec hParamBlock;
- HIOParam ioParam;
- HFileParam fileParam;
- HVolumeParam volumeParam;
- AccessParam accessParam;
- ObjParam objParam;
- CopyParam copyParam;
- WDParam wdParam;
- FIDParam fidParam;
- CSParam csParam;
- ForeignPrivParam foreignPrivParam;
- ParamBlockRec paramBlock;
- }
- tHFS_PBRec;
-
- // HFS parameter block for general i/o calls
-
- typedef struct tHFS_ParamBlockTag
- {
- struct tHFS_ParamBlockTag *fNext; // next param block in list
- tHFS_PBRec fParamBlock; // param block union used by HFS calls
- Str63 fName; // name
- UInt32 fRequestTime; // request time
- SInt16 fAccessRefNum; // access ref num if used in open fork
- }
- tHFS_ParamBlock;
-
- OSErr HFS_ReadCatIndex( // read an indexed catalog entry
- SInt16 pVolume, // the volume
- SInt32 pDirectory, // the directory
- SInt32 pIndex, // the index
- CInfoPBRec *rCatInfo, // returns the data
- unsigned char *rName, // returns the name
- Boolean *rEndOfCatalog) // returns end of catalog
- {
- OSErr rResult = noErr;
- tHFS_ParamBlock vParamBlock;
-
- // get a parameter block
-
- // rResult = HFS_GetParamBlock(NULL, &vParamBlock);
- _ZeroBlock((Ptr)&vParamBlock, sizeof(tHFS_ParamBlock));
- vParamBlock.fParamBlock.ioParam.ioNamePtr = vParamBlock.fName;
-
- // if this is the system root, get the info for the volume
-
- if (!rResult && pVolume == 0)
- {
- vParamBlock.fParamBlock.volumeParam.ioVRefNum = 0;
- vParamBlock.fParamBlock.volumeParam.ioVolIndex = pIndex;
-
- // initiate request to get the volume reference number
-
- rResult = PBHGetVInfoSync(&vParamBlock.fParamBlock.hParamBlock);
-
- // save the results and get another parameter block
-
- if (!rResult)
- {
- pVolume = vParamBlock.fParamBlock.volumeParam.ioVRefNum;
- pDirectory = 2;
- pIndex = -1;
- // rResult = HFS_GetParamBlock(NULL, &vParamBlock);
- _ZeroBlock((Ptr)&vParamBlock, sizeof(tHFS_ParamBlock));
- vParamBlock.fParamBlock.ioParam.ioNamePtr = vParamBlock.fName;
- }
- }
-
- // get the info for the directory
-
- if (!rResult)
- {
- vParamBlock.fParamBlock.dirInfo.ioVRefNum = pVolume;
- vParamBlock.fParamBlock.dirInfo.ioFDirIndex = pIndex;
- vParamBlock.fParamBlock.dirInfo.ioDrDirID = pDirectory;
-
- // initiate catalog info request
-
- rResult = PBGetCatInfoSync(&vParamBlock.fParamBlock.cInfo);
-
-
- // return the result
-
- if (!rResult)
- {
- *rCatInfo = vParamBlock.fParamBlock.cInfo;
- BlockMoveData(vParamBlock.fName, rName, vParamBlock.fName[0] + 1);
- *rEndOfCatalog = FALSE;
- }
- else // rResult
- {
- *rEndOfCatalog = TRUE;
- rResult = noErr;
- }
- }
- else // rResult
- *rEndOfCatalog = TRUE;
-
- return rResult;
- }
-
- static pascal OSErr GetFDFlags(short vRefNum,
- long dirID,
- ConstStr255Param name,
- Boolean *getBits,
- unsigned short flagBits)
- {
- CInfoPBRec pb;
- Str31 tempName;
- OSErr error;
- short realVRefNum;
- long parID;
-
- /* Protection against File Sharing problem */
- if ( (name == NULL) || (name[0] == 0) )
- {
- tempName[0] = 0;
- pb.hFileInfo.ioNamePtr = tempName;
- pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
- }
- else
- {
- pb.hFileInfo.ioNamePtr = (StringPtr)name;
- pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
- }
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- error = PBGetCatInfoSync(&pb);
- if ( error == noErr )
- {
- *getBits = (pb.hFileInfo.ioFlFndrInfo.fdFlags & flagBits) != 0;
- }
-
- return ( error );
- }
-
- OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr,
- FSSpecArrayHandle fah)
- {
- OSErr retCode;
- LaunchParamBlockRec launchParams;
- ProcessSerialNumber myPSN;
- AppleEvent theAppleEvent;
- AEDesc myAddrDesc, launchParamDesc, docDesc;
- AEDescList docDescList;
- AliasHandle docAlias;
- OSErr myErr;
- unsigned short items, index;
-
- AliasHandle documentAlias;
-
-
- // to simplify cleanup, ensure that handles are nil to start
- theAppleEvent.dataHandle = nil;
- launchParamDesc.dataHandle = nil;
- docDescList.dataHandle = nil;
- docDesc.dataHandle = nil;
- docAlias = nil;
-
- // the Apple event will need a valid address descriptor (even though its
- // contents will not matter since we will not be calling AESend) so make
- // one using my own serial number
-
- (void) GetCurrentProcess(&myPSN);
- retCode = AECreateDesc(typeProcessSerialNumber, (Ptr) &myPSN,
- sizeof(ProcessSerialNumber), &myAddrDesc);
- if (retCode != noErr) goto Bail;
-
- // make a descriptor list containing just a descriptor with an
- // alias to the document
-
- retCode = AECreateList(nil, 0, false, &docDescList);
- if (retCode != noErr) goto Bail;
-
- convertfahtoAElist(fah, &docDescList);
-
- // now make the 'odoc' AppleEvent descriptor and insert the
- // document descriptor list as the direct object
-
- retCode = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
- &myAddrDesc, kAutoGenerateReturnID, kAnyTransactionID,
- &theAppleEvent);
- if (retCode != noErr) goto Bail;
-
- retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDescList);
- if (retCode != noErr) goto Bail;
-
- // this Apple event will not be sent but rather will be used
- // as a parameter to the LaunchApplication call, so coerce it
- // to the magic type typeAppParamters
-
- retCode = AECoerceDesc(&theAppleEvent, typeAppParameters, &launchParamDesc);
- if (retCode != noErr) goto Bail;
-
- // finally, fill in the launch parameter block, including the
- // Apple event, and make the launch call
-
- HLock((Handle) launchParamDesc.dataHandle);
- launchParams.launchAppParameters =
- (AppParametersPtr) *(launchParamDesc.dataHandle);
-
- launchParams.launchBlockID = extendedBlock;
- launchParams.launchEPBLength = extendedBlockLen;
- launchParams.launchFileFlags = launchNoFileFlags;
- launchParams.launchControlFlags = launchContinue;
- launchParams.launchAppSpec = (FSSpecPtr) applicationFSSpecPtr;
-
- {
- FInfo fndrInfo;
- FSSpec appFile;
- Boolean wasChanged;
-
- FSpGetFInfo(applicationFSSpecPtr, &fndrInfo);
-
- }
-
- retCode = LaunchApplication(&launchParams);
-
- if(retCode == -108 && launchParams.launchMinimumSize < launchParams.launchAvailableSize) {
- launchParams.launchControlFlags = launchContinue | launchUseMinimum;
- retCode = LaunchApplication(&launchParams);
- }
-
- Bail:
- // dispose of everything that was allocated
-
- if (theAppleEvent.dataHandle != nil) (void) AEDisposeDesc(&theAppleEvent);
- if (launchParamDesc.dataHandle != nil) (void) AEDisposeDesc(&launchParamDesc);
- if (docDescList.dataHandle != nil) (void) AEDisposeDesc(&docDescList);
- if (docDesc.dataHandle != nil) (void) AEDisposeDesc(&docDesc);
- if (launchParamDesc.dataHandle != nil) (void) AEDisposeDesc(&launchParamDesc);
- if (docAlias != nil)
- DisposeHandle((Handle) docAlias);
-
-
- return retCode;
- }
-
- OSErr FindAProcess(OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN,ProcessInfoRecPtr infoRecToFill)
- {
- ProcessInfoRec tempInfo;
- FSSpec procSpec;
- Str31 processName;
- OSErr myErr = noErr;
-
- processSN->lowLongOfPSN = kNoProcess;
- processSN->highLongOfPSN = kNoProcess;
-
- tempInfo.processInfoLength = sizeof(ProcessInfoRec);
- tempInfo.processName = (StringPtr)&processName;
- tempInfo.processAppSpec = &procSpec;
-
- while ((tempInfo.processSignature != creatorToFind || tempInfo.processType != typeToFind ||
- myErr != noErr))
- {
- myErr = GetNextProcess(processSN);
- if (myErr == noErr) {
- GetProcessInformation(processSN, &tempInfo);
- }
- else {
- break;
- }
- }
- if(infoRecToFill)
- *infoRecToFill = tempInfo;
- return myErr;
- }
-
- static Boolean GetIndVRefNum(short which, short *vRefNum, StringPtr name)
- {
- OSErr theErr = noErr;
- short index;
- VolumeParam vpb;
- Str255 volName;
-
- vpb.ioCompletion = nil;
-
- for(index = 1; theErr == noErr; index ++) {
- vpb.ioVolIndex = index;
- vpb.ioNamePtr = name;
- vpb.ioVRefNum = 0;
- theErr = PBGetVInfoSync((ParmBlkPtr)&vpb);
- if( (index == which) && (theErr == noErr) ) {
- *vRefNum = vpb.ioVRefNum;
- return true;
- }
- }
- return false;
- }
-
-
- /**************************************************************************
- *
- * Procedure PlaySoundAsync
- *
- * If preferences allow, play the click sound asynchronously.
- * //sound.h
- **************************************************************************/
- Handle gSound = nil;
- SndChannelPtr gChannel = nil;
- SndCallBackUPP soundCallbackProc;
- static void SoundCallback(SndChannelPtr chan, SndCommand *cmd)
- {
- // dprintf("Channel %08lx, cmd->cmd = %d, param1 = %d, param2 = %08lx", chan, cmd->cmd, cmd->param1, cmd->param2);
- }
-
- void PlaySoundAsync(StringPtr soundName)
- {
- Handle sndHandle;
- OSErr theErr;
-
- if(!soundCallbackProc)
- soundCallbackProc = NewSndCallBackProc(SoundCallback);
-
- if(gChannel) SndDisposeChannel(gChannel, TRUE);
-
- gSound = GetNamedResource('snd ', soundName);
-
- if(gSound) {
- gChannel = nil;
- theErr = SndNewChannel(&gChannel, 5, initMono, soundCallbackProc);
- theErr = SndPlay( gChannel, (SndListHandle)gSound, TRUE );
- }
- }
-
-
- static void SendODOCToProcess(ProcessSerialNumberPtr psn, FSSpecArrayHandle fah)
- {
- short errnum;
- AEDesc targetaddress;
- AEDescList selectionlist;
- AppleEvent myae, myreply;
-
- if (((errnum = AECreateDesc(typeProcessSerialNumber, psn, sizeof(ProcessSerialNumber), &targetaddress)) == noErr) &&
- ((errnum = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &targetaddress, kAutoGenerateReturnID, kAnyTransactionID, &myae)) == noErr) &&
- ((errnum = AEDisposeDesc(&targetaddress)) == noErr) &&
- ((errnum = AECreateList(nil, 0, FALSE, &selectionlist)) == noErr) &&
- ((errnum = convertfahtoAElist(fah, &selectionlist)) == noErr) &&
- ((errnum = AEPutParamDesc(&myae, keyDirectObject, &selectionlist)) == noErr) &&
- ((errnum = AEDisposeDesc(&selectionlist)) == noErr))
- {
-
- if ((errnum == noErr) &&
- ((errnum = AESend(&myae, &myreply, kAENoReply, kAENeverInteract, kAEDefaultTimeout, nil, nil)) == noErr) &&
- ((errnum = AEDisposeDesc(&myreply)) == noErr))
- errnum = AEDisposeDesc(&myae);
- }
-
- }
-
-
- /*-------------*
- | IsAliasFile |
- *-------------*/
- static pascal OSErr IsAliasFile(const FSSpec *fileFSSpec,
- Boolean *aliasFileFlag,
- Boolean *folderFlag)
- /* sets aliasFileFlag if the FSSpec points to an alias file;
- sets folderFlag if the FSSpec points to a folder */
-
- {
- CInfoPBRec myCInfoPBRec;
- OSErr retCode;
-
- if (fileFSSpec == nil || aliasFileFlag == nil || folderFlag == nil)
- return paramErr;
-
- *aliasFileFlag = *folderFlag = false;
-
- /* get the item's catalog information */
- myCInfoPBRec.hFileInfo.ioCompletion = nil;
- myCInfoPBRec.hFileInfo.ioNamePtr = (StringPtr)&fileFSSpec->name;
- myCInfoPBRec.hFileInfo.ioVRefNum = fileFSSpec->vRefNum;
- myCInfoPBRec.hFileInfo.ioDirID = fileFSSpec->parID;
- myCInfoPBRec.hFileInfo.ioFVersNum = 0; /* MFS compatibility, see TN #204 */
- myCInfoPBRec.hFileInfo.ioFDirIndex = 0;
-
- retCode = PBGetCatInfoSync(&myCInfoPBRec);
-
- /* set aliasFileFlag if the item is not a directory and the
- aliasFile bit is set */
-
- if (retCode == noErr) {
- /* check directory bit */
- if ((myCInfoPBRec.hFileInfo.ioFlAttrib & ioDirMask) != 0)
- *folderFlag = true;
-
- /* check isAlias bit */
- else if ((myCInfoPBRec.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) != 0)
- *aliasFileFlag = true;
- }
-
- return retCode;
- }
-
-
- /*-----------------------------*
- | ResolveAliasFileMountOption |
- *-----------------------------*/
- pascal OSErr ResolveAliasFileMountOption(FSSpec *fileFSSpec,
- Boolean resolveAliasChains,
- Boolean *targetIsFolder,
- Boolean *wasAliased,
- Boolean mountRemoteVols)
- {
- /* maximum number of aliases to resolve before giving up */
- #define MAXCHAINS 10
-
- short myResRefNum;
- Handle alisHandle;
- FSSpec initFSSpec;
- Boolean updateFlag, foundFlag, wasAliasedTemp, specChangedFlag;
- short chainCount;
- OSErr retCode;
-
- if (fileFSSpec == nil || targetIsFolder == nil || wasAliased == nil)
- return paramErr;
-
- initFSSpec = *fileFSSpec; /* so FSSpec can be restored in case of error */
- chainCount = MAXCHAINS; /* circular alias chain protection */
- myResRefNum = -1; /* resource file not open */
-
- *targetIsFolder = foundFlag = specChangedFlag = false;
-
- /* loop through chain of alias files */
- do {
- chainCount--;
-
- /* check if FSSpec is an alias file or a directory */
- /* note that targetIsFolder => NOT wasAliased */
-
- retCode = IsAliasFile(fileFSSpec, wasAliased, targetIsFolder);
- if (retCode != noErr || !(*wasAliased)) break;
-
- /* get the resource file reference number */
- myResRefNum = FSpOpenResFile(fileFSSpec, fsCurPerm);
- retCode = ResError();
- if (myResRefNum == -1) break;
-
- /* the first 'alis' resource in the file is the appropriate alias */
- alisHandle = Get1IndResource(rAliasType, 1);
- retCode = ResError();
- if (alisHandle == nil) break;
-
- /* load the resource explicitly in case SetResLoad(FALSE) */
- LoadResource(alisHandle);
- retCode = ResError();
- if (retCode != noErr) break;
-
- retCode = FollowFinderAlias(fileFSSpec, (AliasHandle) alisHandle,
- mountRemoteVols, fileFSSpec, &updateFlag);
- /* FollowFinderAlias returns nsvErr if volume not mounted */
-
- if (retCode == noErr) {
-
- if (updateFlag) {
- /* the resource in the alias file needs updating */
- ChangedResource(alisHandle);
- WriteResource(alisHandle);
- }
-
- specChangedFlag = true; /* in case of error, restore file spec */
-
- retCode = IsAliasFile(fileFSSpec, &wasAliasedTemp, targetIsFolder);
- if (retCode == noErr)
- /* we're done unless it was an alias file and we're following a chain */
- foundFlag = !(wasAliasedTemp && resolveAliasChains);
-
- }
-
- CloseResFile(myResRefNum);
- myResRefNum = -1;
-
- } while (retCode == noErr && chainCount > 0 && !foundFlag);
-
- /* return file not found error for circular alias chains */
- if (chainCount == 0 && !foundFlag) retCode = fnfErr;
-
- /* if error occurred, close resource file and restore the original FSSpec */
- if (myResRefNum != -1) CloseResFile(myResRefNum);
- if (retCode != noErr && specChangedFlag) *fileFSSpec = initFSSpec;
-
- return retCode;
- }
-
- /*What's left for making a real game of it?*/
- /*- Animations*/
- /*- Several levels*/
- /*- Faster drawing*/
- /*- Asynch sound*/
- /*- More objects, i.e. weapons, monsters, treasures…*/